#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
API管理器
负责TqSdk API的连接和管理
"""

import asyncio
from typing import Dict, Any, Optional, List
from contextlib import asynccontextmanager

from tqsdk import TqApi, TqAuth, TqSim

from config.config_manager import get_config
from utils.logger import get_logger
from utils.exceptions import (
    APIError, AuthenticationError, ConnectionError, TimeoutError,
    SymbolNotFoundError, DataUnavailableError
)
from core.base_classes import BaseComponent


class APIManager(BaseComponent):
    """API管理器"""

    def __init__(self):
        super().__init__("APIManager")
        self.config = get_config()
        self.api = None
        self.auth = None
        self.is_connected = False
        self.connection_attempts = 0
        self.max_connection_attempts = 3

    async def initialize(self):
        """初始化API连接"""
        try:
            self.logger.info("开始初始化API连接...")

            # 创建认证对象
            if self.config.api.account and self.config.api.password:
                self.auth = TqAuth(self.config.api.account, self.config.api.password)
                self.logger.info("使用实盘账户认证")
            else:
                self.logger.warning("未配置实盘账户，使用模拟账户")
                self.auth = None

            # 创建API实例
            if self.config.trading.enable_simulation or not self.auth:
                self.api = TqApi(
                    account=TqSim(),
                    debug=self.config.api.debug,
                    web_gui=self.config.api.web_gui
                )
                self.logger.info("创建模拟交易API实例")
            else:
                self.api = TqApi(
                    auth=self.auth,
                    url=self.config.api.url,
                    debug=self.config.api.debug,
                    web_gui=self.config.api.web_gui
                )
                self.logger.info("创建实盘交易API实例")

            # 等待连接建立
            await self._wait_for_connection()

            self.is_connected = True
            self.logger.info("API连接初始化成功")

        except Exception as e:
            self.logger.error(f"API连接初始化失败: {e}")
            raise ConnectionError(f"API连接初始化失败: {e}")

    async def _wait_for_connection(self, timeout: int = 30):
        """等待连接建立"""
        import time
        start_time = time.time()

        while time.time() - start_time < timeout:
            try:
                # 检查连接状态
                if hasattr(self.api, '_data') and self.api._data:
                    return
                await asyncio.sleep(0.1)
            except Exception as e:
                self.logger.warning(f"连接检查失败: {e}")
                await asyncio.sleep(1)

        raise TimeoutError("API连接超时")

    async def cleanup(self):
        """清理API资源"""
        if self.api:
            try:
                self.api.close()
                self.logger.info("API连接已关闭")
            except Exception as e:
                self.logger.error(f"关闭API连接时出错: {e}")

        self.is_connected = False

    async def get_quote(self, symbol: str) -> Dict[str, Any]:
        """获取实时行情"""
        if not self.is_connected:
            raise ConnectionError("API未连接")

        try:
            quote = self.api.get_quote(symbol)

            # 检查合约是否存在
            if not hasattr(quote, 'last_price') or quote.last_price != quote.last_price:  # 检查NaN
                raise SymbolNotFoundError(f"合约不存在或数据不可用: {symbol}")

            return {
                'symbol': symbol,
                'last_price': quote.last_price,
                'bid_price1': quote.bid_price1,
                'bid_volume1': quote.bid_volume1,
                'ask_price1': quote.ask_price1,
                'ask_volume1': quote.ask_volume1,
                'volume': quote.volume,
                'open_interest': quote.open_interest,
                'highest': getattr(quote, 'highest', quote.last_price),
                'lowest': getattr(quote, 'lowest', quote.last_price),
                'datetime': quote.datetime
            }

        except SymbolNotFoundError:
            raise
        except Exception as e:
            self.logger.error(f"获取行情失败 {symbol}: {e}")
            raise APIError(f"获取行情失败 {symbol}: {e}")

    async def get_kline_data(self, symbol: str, period: int, length: int) -> Dict[str, Any]:
        """获取K线数据"""
        if not self.is_connected:
            raise ConnectionError("API未连接")

        try:
            klines = self.api.get_kline_serial(symbol, period, data_length=length)

            return {
                'symbol': symbol,
                'period': period,
                'data': klines,
                'length': len(klines)
            }

        except Exception as e:
            self.logger.error(f"获取K线数据失败 {symbol}: {e}")
            raise APIError(f"获取K线数据失败 {symbol}: {e}")

    async def get_tick_data(self, symbol: str, length: int) -> Dict[str, Any]:
        """获取Tick数据"""
        if not self.is_connected:
            raise ConnectionError("API未连接")

        try:
            ticks = self.api.get_tick_serial(symbol, data_length=length)

            return {
                'symbol': symbol,
                'data': ticks,
                'length': len(ticks)
            }

        except Exception as e:
            self.logger.error(f"获取Tick数据失败 {symbol}: {e}")
            raise APIError(f"获取Tick数据失败 {symbol}: {e}")

    async def insert_order(self, symbol: str, direction: str, offset: str,
                          volume: int, price: Optional[float] = None) -> str:
        """下单"""
        if not self.is_connected:
            raise ConnectionError("API未连接")

        try:
            order = self.api.insert_order(
                symbol=symbol,
                direction=direction,
                offset=offset,
                volume=volume,
                limit_price=price
            )

            self.logger.info(f"下单成功: {symbol} {direction} {offset} {volume}手 价格:{price}")
            return order.order_id

        except Exception as e:
            self.logger.error(f"下单失败 {symbol}: {e}")
            raise APIError(f"下单失败 {symbol}: {e}")

    async def cancel_order(self, order_or_order_id) -> bool:
        """撤单"""
        if not self.is_connected:
            raise ConnectionError("API未连接")

        try:
            self.api.cancel_order(order_or_order_id)
            self.logger.info(f"撤单成功: {order_or_order_id}")
            return True

        except Exception as e:
            self.logger.error(f"撤单失败 {order_or_order_id}: {e}")
            raise APIError(f"撤单失败 {order_or_order_id}: {e}")

    async def get_order(self, order_id: Optional[str] = None):
        """获取订单信息"""
        if not self.is_connected:
            raise ConnectionError("API未连接")

        try:
            return self.api.get_order(order_id)
        except Exception as e:
            self.logger.error(f"获取订单信息失败 {order_id}: {e}")
            raise APIError(f"获取订单信息失败 {order_id}: {e}")

    async def get_trade(self, trade_id: Optional[str] = None):
        """获取成交信息"""
        if not self.is_connected:
            raise ConnectionError("API未连接")

        try:
            return self.api.get_trade(trade_id)
        except Exception as e:
            self.logger.error(f"获取成交信息失败 {trade_id}: {e}")
            raise APIError(f"获取成交信息失败 {trade_id}: {e}")

    async def get_position(self, symbol: Optional[str] = None):
        """获取持仓信息"""
        if not self.is_connected:
            raise ConnectionError("API未连接")

        try:
            return self.api.get_position(symbol)
        except Exception as e:
            self.logger.error(f"获取持仓信息失败 {symbol}: {e}")
            raise APIError(f"获取持仓信息失败 {symbol}: {e}")

    async def get_account(self):
        """获取账户信息"""
        if not self.is_connected:
            raise ConnectionError("API未连接")

        try:
            return self.api.get_account()
        except Exception as e:
            self.logger.error(f"获取账户信息失败: {e}")
            raise APIError(f"获取账户信息失败: {e}")

    async def wait_update(self, deadline: Optional[float] = None):
        """等待数据更新"""
        if not self.is_connected:
            raise ConnectionError("API未连接")

        try:
            return self.api.wait_update(deadline=deadline)
        except Exception as e:
            self.logger.error(f"等待更新失败: {e}")
            raise APIError(f"等待更新失败: {e}")

    def is_changing(self, obj, field: str = None):
        """检查对象是否发生变化"""
        if not self.is_connected:
            return False

        try:
            if field:
                return self.api.is_changing(obj, field)
            else:
                return self.api.is_changing(obj)
        except Exception as e:
            self.logger.error(f"检查对象变化失败: {e}")
            return False

    async def get_health_status(self) -> Dict[str, Any]:
        """获取API健康状态"""
        try:
            return {
                'is_connected': self.is_connected,
                'connection_attempts': self.connection_attempts,
                'has_auth': self.auth is not None,
                'is_simulation': isinstance(getattr(self.api, '_account', None), TqSim) if self.api else False
            }
        except Exception as e:
            self.logger.error(f"获取健康状态失败: {e}")
            return {
                'is_connected': False,
                'error': str(e)
            }


# 全局API管理器实例
_api_manager = None

def get_api_manager() -> APIManager:
    """获取全局API管理器实例"""
    global _api_manager
    if _api_manager is None:
        _api_manager = APIManager()
    return _api_manager

async def init_api_manager() -> APIManager:
    """初始化API管理器"""
    global _api_manager
    _api_manager = APIManager()
    await _api_manager.initialize()
    return _api_manager

@asynccontextmanager
async def api_context():
    """API上下文管理器"""
    manager = await init_api_manager()
    try:
        yield manager
    finally:
        await manager.cleanup()
